import { ref, onUnmounted } from 'vue'
import { isFunction, has } from 'lodash-es'
import { getCache, setCache } from './cache'
import { subscribe, trigger } from './cacheSubscribe'
import { setCacheFetch, getCacheFetch } from './cacheFetch'

import type { FP } from '../../types'
import type { CacheData, CacheKey } from './types'

const useCachePlugin: FP = (
  fetchInstance,
  { cacheKey: customCacheKey, cacheTime = 600000, staleTime = 0, getCache: customGetCache, setCache: customSetCache }
) => {
  if (!customCacheKey) return {}

  const cacheKey = isFunction(customCacheKey) ? customCacheKey : () => customCacheKey

  const unSubscribe = ref(() => {})

  let currentFetch: Promise<any>

  const _getCache = (key: CacheKey) => {
    if (customGetCache) {
      return customGetCache(key)
    } else {
      return getCache(key)
    }
  }

  const _setCache = (key: CacheKey, time: number, cacheData: CacheData) => {
    if (customSetCache) {
      customSetCache(key, cacheData)
    } else {
      setCache(key, time, cacheData)
    }
    trigger(key, cacheData.data)
  }

  const isFresh = (time: number) => {
    return staleTime === -1 || time + staleTime > Date.now()
  }

  const subscribeCache = (params?: any[]) => {
    const _cacheKey = cacheKey(params)
    return subscribe(_cacheKey, data => {
      fetchInstance.data.value = data
    })
  }

  // ----- 初始化 -----
  const _cacheKey = cacheKey()
  const cache = _getCache(_cacheKey)
  if (cache && has(cache, 'data')) {
    fetchInstance.data.value = cache.data
    fetchInstance.params.value = cache.params
  }

  // ----- 监听 -----
  if (_cacheKey) {
    unSubscribe.value = subscribeCache()
  }

  onUnmounted(() => {
    unSubscribe.value()
  })

  return {
    onBefore(params) {
      const _cacheKey = cacheKey(params)
      const cache = _getCache(_cacheKey)

      if (!cache || !has(cache, 'data')) return {}

      // 如果还是保鲜期内，则不请求数据
      if (isFresh(cache.time)) {
        return {
          isReturn: true,
          loading: false,
          data: cache.data
        }
      } else {
        // 如果不是新鲜期内的，则重新请求并设置数据
        return {
          data: cache.data
        }
      }
    },

    onFetch(service) {
      const params = fetchInstance.params.value
      const _cacheKey = cacheKey(params)
      let servicePromise = getCacheFetch(_cacheKey)

      if (servicePromise && servicePromise !== currentFetch) {
        return () => servicePromise
      }

      servicePromise = service()
      currentFetch = servicePromise
      setCacheFetch(_cacheKey, servicePromise)
      return () => servicePromise
    },

    onSuccess(data, params) {
      const _cacheKey = cacheKey(params)
      if (_cacheKey) {
        unSubscribe.value()

        _setCache(_cacheKey, cacheTime, { data, params, time: Date.now() })

        unSubscribe.value = subscribeCache(params)
      }
    },

    onMutate(data) {
      const _cacheKey = cacheKey(fetchInstance.params.value)
      if (_cacheKey) {
        unSubscribe.value()

        _setCache(_cacheKey, cacheTime, { data, params: fetchInstance.params.value, time: Date.now() })

        unSubscribe.value = subscribeCache(fetchInstance.params.value)
      }
    }
  }
}

export default useCachePlugin
